/*	================================================================================
	Core file
	Author: 		Ben Haldenby - http://benhaldenby.co.uk
					Philip Poole - http://welovenicethings.com
				
	Date:			2009-03-26
	Description: 	jFrame framework
	================================================================================ */
	
/**
* $
* @namespace $
* Maintains the standard jQuery namespace.
*/
$=$;


/**
 * Allow namespaces to be created so we can use them in jQuery plugins.
 * 
 * Without using this method, if you tried to create a jQuery plugin such as: $.jFrame.myplugin and call it as
 * $('mydiv').jFrame().myplugin the plugin will fail as the element 'mydiv' does not get passed to theplugin.
 * 
 * By calling $.namespace('jFrame'); The element will get passed to the plugin correctly.
 * 
 * Code from http://youngisrael-stl.org/wordpress/2008/08/05/namespaces-in-jquery/
 * 
 * @param {Object} The namespace to add
 */
(function($){ 
	if ({}.__proto__){ 
		// mozilla	& webkit expose the prototype chain directly 

		$.namespace = function(name){ 
			$.fn[name] = function namespace() { // insert this function in the prototype chain 
				this.__proto__ = arguments.callee; 
				return this; 
			}; 
			$.fn[name].__proto__ = $.fn; 
		}; 

		$.fn.$ = function(){ 
			this.__proto__ = $.fn; 
			return this; 
		};	   
	}else{ 
		// every other browser; need to copy methods

		$.namespace = function(name){ 
			$.fn[name] = function namespace() { return this.extend(arguments.callee); }; 
		}; 

		$.fn.$ = function() { // slow but restores the default namespace 
			var len = this.length; 
			this.extend($.fn); 
			this.length = len; // $.fn has length = 0, which messes everything up 
			return this; 
		}; 
	} 
})(jQuery); 
	




/**
 * The core namespace for all British Museum JavaScript functionality.
 * 
 * <p>Rather than calling many JavaScript files from HTML we will use a core framework that 
 * references all JavaScript files. With this technique the HTML pages call the framework 
 * to access any JavaScript functionality they need, including but not limited to: third-party jQuery plugins, sIFR, 
 * Nifty Corners and custom jFrame UI components (such as Slideshows, Randomisers, etc).
 * The framework will then load all supporting JavaScript files necessary for the required functionaility 
 * (for instance, the HideShow component requires the jQuery UI FX library).
 * This therefore seperates the JavaScript dependancies from the markup (HTML).</p>
 * 
 * <p>If you have a large website with different sections using very different pieces of JavaScript, 
 * the famework is very useful as you need only load the functionality you want, as and when you need it.
 * With very large content-managed sites it is better to do this than load all JavaScript in one go as the majority of users
 * may only use a small part of what is loaded.</p>
 * 
 * <p>However if you do wish to load all JavaScript in one go, a preloader has been provided 
 * that can be called from page(s) of your choosing.</p>
 * 
 * <p>The framework provides callbacks, which allow you to execute your own arbitrary functions 
 * once JavaScript files have been loaded.</p>
 * 
 * <p>To minimise network traffic and make best use of browser caching, if JavaScript files are called repeatedly, the framework 
 * will only fetch a given file once while still executing any callbacks attached to those requests.</p>
 * 
 * <p>Each JavaScript file that is called can be set to be cached in the browser, therefore decreasing the page 
 * load times if the same functionality is called on other pages.</p>
 * 
 * <p>A debugger has been created that can be utilised across components. This debugger uses console.log() but wraps that method so as
 * not to throw an error in browsers that don't support it (Internet Explorer, we're looking at you). The debugger also has a verbosity setting
 * allowing you to add debug outpus with a set verbosity. Therefore the debugger will only output debug outputs that are equal to or lower
 * than the set verbosity.</p>
 * 
 * @namespace
 */
$.jFrame = {};

/**
 *  Create the jFrame namespace so plugins can use it.
 */
$.namespace('jFrame');


// start of the jFrame object
(function($) {
	/**
	* <p>This object contains all of the core British Museum components. The useComponent method uses this object 
	* to load the components' external .js files and initiate them.</p>
	* 
	* <p>You can add to this by calling addComponent().</p>
	*
	* <p>Each component has the following properties:</p>
	* <ul>
	*	<li>url: The URL of the JavaScript, this can be a relative or absolute URL. [String].</li>
	*	<li>loaded: Specifies whether or not the file is loaded. [Boolean].</li>
	*	<li>cache: Specifies whether or not to cache the file. [Boolean].</li>
	* 	<li>execute: An optional method which can be run after the JavaScript has been loaded. [Callback function].</li>
	* </ul>
	*
	* <p>Add to this using the addComponent() method. Do not hard code to this directly.</p>
	* @private
	*/
	$.jFrame.components = {};
		
	
	/**
	 * <p>Add your own JavaScript component to the components list.</p> 
	 * 
	 * <p>By calling addComponent(), the component is added to the 'components' collection ready for use later on. 
	 * The callback that you specify is called later on within the start() method.</p>
	 *
	 *	@example
	 *		$.jFrame.addComponent('componentname', 
	 *			'javascripts/v2/myscript.js',
	 *			true, 
	 *			function() {
	 *				alert("This callback runs when the component's start() method is called.");
	 *			};
	 *
	 *	<p>You can then load in the JavaScript when you need it by calling:</p>
	 *
	 *	@example 
	 *		$.jFrame.start('componentname', 
	 *			function() {
	 *				alert("myCallback");
	 *			};
	 * 
 	 * <p>Please note that if you specify to cache the JavaScript URL and subsequently change the script, you
	 * will have to change the filename of the script in order to ensure that the updated version is requested from the server.</p>
	 * 
	 * @param {Object} name 	The name you want to call your component (required).
	 * @param {Object} url		The URL of the JavaScript (required).
	 * @param {Object} cache 	Whether the JavaScript can be cached by the browser (required).
	 * @param {Object} execute 	Optional function to be executed whenever the script is called using the start() method (optional).
	 */
	$.jFrame.addComponent = function(name, url, cache, execute){
		//check component does not already exist		
		if (this.components[name] != undefined) {
			throw Error("$.jFrame.addComponent: Component already exists");
		}

		//add component in
		this.components[name] = {
			url: url, 
			loaded: false, 
			cache: cache,
			execute: execute
		};
								 
		$.jFrame.debug('$.jFrame.addComponent: A component has been added: ', name, $.jFrame.debug.debugVerbosity.medium);
	};
	
	
	
	
	/**
	* <p>Loads a number of JavaScript files based on the component names that is passed into it.</p>
	* 
	* <p>You can specify one or more components, after the last component is loaded an optional 
	* callback will then be executed.</p>
	* 
	* <p>This method is most usefully called from plugins whereas the start() 
	* method is most usefully called from within the HTML.</p>
	*
	* @param {string} components Component names taken from the $.jFrame.components object in a comma seperated list. (required)
	* @param {string} callbackFunction The callback function to be run after loading the last file. (optional)
	* 
	* @example $.jFrame.useComponents('thickbox,lightbox', function () {
	*	alert('JavaScript files have been loaded');
	* });
	*/	
	$.jFrame.useComponents = function(components,callbackFunction) {

		$.jFrame.debug('$.jFrame.useComponents: About to load different components: ', components,  $.jFrame.debug.debugVerbosity.high);
		componentList = components.split(",");
		
		//load each component in turn.
		for (var i=0; i < componentList.length; i++) {
			//strip out any spaces
			var component = componentList[i].replace(/^\s*/, "").replace(/\s*$/, "");

			if (i== (componentList.length - 1)) {
				//this is the last component so call the callback Function if one has been supplied
				$.jFrame.useComponent(component, callbackFunction);
			} else {
				$.jFrame.useComponent(component, null);
			}	
		}
	};


	/**
	* <p>Loads a JavaScript file based on the component name that is passed into it.</p>
	* 
	* <p>An optional callback is executed after the file has been sucessfully called.</p>
	*
	* @param {string} component Component name taken from the $.jFrame.components object. (required)
	* @param {string} callbackFunction The callback function to be run after loading the file. (optional)
	* 
	* @example $.jFrame.useComponent('thickbox,', function () {
	*	alert('JavaScript file has been loaded');
	* });
	* 
	* @private 
	*/
	$.jFrame.useComponent = function(component, callbackFunction){
		$.jFrame.debug('$.jFrame.useComponent: About to load component: ', component,  $.jFrame.debug.debugVerbosity.medium);

		// Get a reference to the component in the components object
		var c = this.components[component];

		if (c == undefined) {
			throw ('An unknown component has been detected, the component name is: ' + component);
		}

		//if JavaScript is already loaded or the url is the same as this file then
		//no need to get file, just set load to true and execute any callback.
		//also do not want to recursively call this file.
		if ( (c && c.loaded === true) || (c.url == $.jFrame.filename) ) {
			$.jFrame.debug('$.jFrame.useComponent: Component was already loaded or refers to this file so only execute the callback: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
			
			c.loaded = true;
			if (callbackFunction) {
				callbackFunction();
				$.jFrame.debug('$.jFrame.useComponent: Call back finished of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
			}	
			//do not want to execute the rest of method so get out.
			return;
		}
	

		// If component exists and it is not loaded
		if(c && c.loaded === false){
			// Load the script using jQuery.getScript()
			$.ajax({
				type: "GET",
				url: c.url,
				dataType: "script",
				cache: c.cache,
				error: function() {
					throw Error("$.jFrame.useComponent: JavaScript was not found for component: " + component);
				},
				success: function(){
					// Set the component's loaded property to true
					c.loaded = true;
					$.jFrame.debug('$.jFrame.useComponent: Component has been loaded: '+ component, null,  $.jFrame.debug.debugVerbosity.medium);
					
					// Run the callbackFunction if one was passed in
					if(callbackFunction) {
						$.jFrame.debug('$.jFrame.useComponent: About to execute callback of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
						callbackFunction();	
						$.jFrame.debug('$.jFrame.useComponent: Finish executing callback of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);				
					}
				}
			});
			$.jFrame.debug('$.jFrame.useComponent: Finished adding component: '+ component, null,  $.jFrame.debug.debugVerbosity.medium);
		}
	};
	
	/**
	* <p>Starts a component, this is the prefered method of initiating a component from within the HTML.</p>
	*
	* <p>A component can have an optional function that is called after the JavaScript component is loaded.
	* We call this a start method. A start method is executed after a component is loaded. This feature can 
	* be useful for plugins that execute automatically without any further commands. The Slideshow is a good 
	* example of this.</p>
	*
	* <p>A callback can be called. This is executed after the JavaScript is loaded but before any start method
	* associated with the component.</p>
	* 
    * <p>A third component can also be added which is executed after any start method.</p>
    * 
	* <p>This method is most usefully called from HTML whereas the useComponents method
	* is most usefully called from inside a plugin (for instance, if a componetn requires a supporting library such as jQuery UI).</p>
    * 
	* @example $.jFrame.start('thickbox');
	* 
	* @example $.jFrame.start('thickbox,', function () {
	*	alert('Callback fucntion');
	* });
	* 
	* @example $.jFrame.start('thickbox,', 
	* 		function () {
	*			alert('Callback function before start method');
	* 		},
	* 		function () {
	*			alert('Callback function after start method');
	* 		});
    *  
	* @param {string} component Component name taken from the $.jFrame.components object. (required)
	* @param {string} callbackFunction The callback function execute before a start method. (optional)
	* @param {string} executeCallbackFunction A callback function that can be run a start method. (optional)
	*/
	$.jFrame.start = function(component, callbackFunction, executeCallbackFunction) {
		$.jFrame.debug('$.jFrame.start: About to start component: '+ component, null, $.jFrame.debug.debugVerbosity.medium);
		var c = this.components[component];

		$.jFrame.useComponents(component, function() {
			if (callbackFunction) {
				$.jFrame.debug('$.jFrame.start: About to execute callback of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
				callbackFunction();
				$.jFrame.debug('$.jFrame.start: Finished executing callback of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
			}
			if (c.execute) {
				$.jFrame.debug('$.jFrame.start: Start method exists, now going to execute it from component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
				c.execute();
				$.jFrame.debug('$.jFrame.start: Finished executing start method of component: '+ component, null,  $.jFrame.debug.debugVerbosity.high);
			}
		});
		
		if(executeCallbackFunction) {
			$.jFrame.debug('$.jFrame.start: Execute callback function exists, going to execute it from component: '+ component, null, $.jFrame.debug.debugVerbosity.high);
			executeCallbackFunction();
			$.jFrame.debug('$.jFrame.start: Finished executing callback function from component: '+ component, null, $.jFrame.debug.debugVerbosity.high);
		}	
		$.jFrame.debug('$.jFrame.start: method finished: '+ component, null, $.jFrame.debug.debugVerbosity.medium);
	};
	
	
   /**
	* <p>This function preloads all of the .js files in the $.jFrame.components object. 
	* This can be called from any page on the site, although it might be best to call it only once on the homepage.</p>
	* 
	* @example $.jFrame.preloader();
	*/
	$.jFrame.preloader = function() {
		$.jFrame.debug('$.jFrame.preloader: Start preloader.', null, $.jFrame.debug.debugVerbosity.medium);

		// Create a ref to the components object
		var c = $.jFrame.components;
		
		// Loop through components
		for (var i in c) {
			// Create a ref to the component's url
			var url = c[i].url;
			
			// If component is not loaded
			if (c[i].loaded == false) {
				
				$.jFrame.debug('$.jFrame.preloader: About to load: '+ c[i], null, $.jFrame.debug.debugVerbosity.high);

				// Call the useComponent() method and pass in the component and a callback function
				$.jFrame.useComponent(i, function(){
					c[i].loaded = true;
				});
			} else {
				$.jFrame.debug('$.jFrame.preloader: Component was already loaded: '+ c[i], null, $.jFrame.debug.debugVerbosity.high);

			}
		}
	};
	
	

})(jQuery); 


(function($) {
		
	/**
	* <p>The framework debugger.</p>
	* 
	* <p>This uses console.log to output to Firebug, however the function is wrapped so that
	* an error is not thrown in browsers that don't support console.log (such as Internet Explorer).</p>
	* 
	* <p>You can also optionally set the verbosity of any debugger outputs. There are three settings:
	* <ul>
	* 	<li>low</li>
	* 	<li>medium</li>
	* 	<li>high</li>
	* </ul>
	* 
	* <p>If you do not set a verbosity, the debugger will always output the set message.</p>
	* 
	* <p>Much of the framework uses medium and high verbosity. Therefore we recommend that most simple plugins 
	* should use a low verbosity. You can then toggle a high or medium verbosity to debug any problems with
	* the framework.</p>
	* 
	* <p>In order to set the verbosity you need to change the value of $.jFrame.debug.currentDebugVerbosity. This
	* is a public variable so you can change this through the course of your code if needed.</p>
	* 
	* <p>You can also turn the debugger off by setting $.jFrame.debug.debugOn to false.</p>
	* 
	* @class
	* @param {string} msg The message that you want to send to the debugging console.
	* @param {string} optionalParam An extra message or variable that you want to send to the debugging console.
	* @param {$.jFrame.debug.debugVerbosity} verbosity A set verbosity for the message.
	* 
	* @example 
	* //simple
	* $.jFrame.debug('Hello world');
	* 
	* @example 
	* //with variable
	* $.jFrame.debug('Hello world: ' + myVar +" good bye world");
	* 
	* @example 
	* //width variable
	* $.jFrame.debug('Hello world', myVar);
	* 
	* @example 
	* //with verbosity
	* $.jFrame.debug('Hello world', myVar, $.jFrame.debug.debugVerbosity.high);
	*/
	$.jFrame.debug = function(msg, optionalParam, verbosity){

		//if console does not exist (IE browsers) or debug is set to off, leave debugger
		if ((typeof console === 'undefined') || !$.jFrame.debug.debugOn) {
			return false;
		}
			
		//if there is not verbosity set, or verbosity is equal or under the current priority, continue.
		if (verbosity == null || verbosity <= $.jFrame.debug.currentDebugVerbosity) 
		{ 
			if (optionalParam != null) {
				console.log(msg, optionalParam);
			} else {
				console.log(msg);
			}
		}	
	};
	
	/**
	 * <p>The different verbosity levels availble for use.</p>
	 * 
	 * <p>You can have:</p>
	 * <ul>
	 * 	<li>low</li>
	 * 	<li>medium</li>
	 * 	<li>high</li>
	 * </ul>
	 */
	$.jFrame.debug.debugVerbosity = {
		low: 0, 
		medium: 1, 
		high: 2 
	};
	
	/**
	* The current debugging verbosity
	*/
	$.jFrame.debug.currentDebugVerbosity = $.jFrame.debug.debugVerbosity.low;
	
	/***
	 * Sets whether the debugger is on or not
	 */
	$.jFrame.debug.debugOn = true;

})(jQuery); 



/* ############################### ******** Make changes under here ********** ############################### 
	1) Change the path of $.jFrame.filename to path of jFrame.js
	2) Add components to jFrame
	3) Create any namescapes
	4) Start any core functionality for all pages
*/


/* ############################### Path of jFrame.js  */
/**
 * The name and relative path of this file.
 * 
 * This is used as a check so if you have compressed core files into jFrame, the system will not recursively call the core file.
 *
 */
$.jFrame.filename = 'jFrame.js';


/* ############################### Here we add all the components into the framework:

	For example:
		$.jFrame.addComponent('survey','javascripts/v1/components/survey.js', false);

*/


/* ############################### Create any namespaces 

	For example:
		$.Example = {};
		$.namespace("Example");
*/			


/* ############################### Below is the core functionality that should be started on every page.  */	
// Default actions to happen on startup for any page.
$(document).ready(function(){
	// Add 'js' to the body class so we can easily render pages differently when JavaScript is enabled.
	$('body').addClass('js');
});

